package us.gaaoc.framework.util;

import java.util.Date;
import java.util.List;
import java.util.UUID;

import us.gaaoc.cms.sustain.vo.CaseDocument;
import us.gaaoc.cms.sustain.vo.CaseEvent;
import us.gaaoc.cms.sustain.vo.CaseFiling;
import us.gaaoc.cms.sustain.vo.CaseOfficial;
import us.gaaoc.cms.sustain.vo.CaseParty;
import us.gaaoc.framework.dao.ModelFacade;
import us.gaaoc.framework.dao.ModelFacadeHibernate;
import us.gaaoc.framework.model.Address;
import us.gaaoc.framework.model.AddressCategory;
import us.gaaoc.framework.model.AddressType;
import us.gaaoc.framework.model.Attorney;
import us.gaaoc.framework.model.CaseRecord;
import us.gaaoc.framework.model.CaseRecordEventType;
import us.gaaoc.framework.model.CaseRecordHistory;
import us.gaaoc.framework.model.CaseRecordStatus;
import us.gaaoc.framework.model.CaseRecordType;
import us.gaaoc.framework.model.Court;
import us.gaaoc.framework.model.CourtEventType;
import us.gaaoc.framework.model.CourtEvents;
import us.gaaoc.framework.model.DocumentInstance;
import us.gaaoc.framework.model.DocumentStatus;
import us.gaaoc.framework.model.Documents;
import us.gaaoc.framework.model.LocalCaseCategory;
import us.gaaoc.framework.model.LocalCaseDivision;
import us.gaaoc.framework.model.LocalCaseFilingType;
import us.gaaoc.framework.model.LocalCaseType;
import us.gaaoc.framework.model.OrgParticipants;
import us.gaaoc.framework.model.OrganizationAddress;
import us.gaaoc.framework.model.Organizations;
import us.gaaoc.framework.model.ParticipantRelationship;
import us.gaaoc.framework.model.Person;
import us.gaaoc.framework.model.PersonAddress;
import us.gaaoc.framework.model.PersonParticipants;

/**
 * This class has a method to save a CMS filing to the MYSQL data model.
 * 
 * @author hea
 * @date July 11, 2007
 */

public class CaseFilingPersistor {

	// public void saveToDataModel(CaseFiling filing, Court court) {
	public String saveToDataModel(CaseFiling filing, Court court) {
		CaseRecord c = null;
		if ((filing != null)) {
			c = this.getModelFacade().findCaseRecordByDocketID(
					filing.getDocketID(), court.getUuid());

			if (c == null) {
				// 1. Save caseRecord
				c = this.insertCaseRecord(filing, court);

				// 2. save participants

				List<CaseParty> ipoList = filing
						.getCaseInitiatingPartyOrgList();
				List<CaseParty> ippList = filing.getInitatingPartyPersonList();
				List<CaseParty> dppList = filing.getCaseDefendantParty();
				List<CaseParty> witList = filing.getWitnessList();
				List<CaseOfficial> ipaList = filing
						.getProsecutionAttorneyList();
				List<CaseOfficial> dpaList = filing.getDefenseAttorneyList();

				if (ipoList != null && !ipoList.isEmpty()) {
					for (CaseParty cp : ipoList) {
					this.insertOrgParticipant(c, cp, 1);
					}
				}

				if (ippList != null && !ippList.isEmpty()) {
					for (CaseParty cp : ippList) {
						this.insertPersonParticipant(c, cp, 1);
					}
				}

				if (dppList != null && !dppList.isEmpty()) {
					for (CaseParty cp : dppList) {
						this.insertPersonParticipant(c, cp, 2);
					}
				}

				if (witList != null & !witList.isEmpty()) {
					for (CaseParty cp : witList) {
						this.insertPersonParticipant(c, cp, 3);
					}
				}

				if (ipaList != null && !ipaList.isEmpty()) {
					for (CaseOfficial co : ipaList) {
						this.insertAttorneyParticipant(c, co, 4);
					}
				}

				if (dpaList != null && !dpaList.isEmpty()) {
					for (CaseOfficial co : dpaList) {
						this.insertAttorneyParticipant(c, co, 5);
					}
				}

				// 3. save documents
				List<CaseDocument> documents = filing.getDocuments();
				if (documents != null && !documents.isEmpty()) {
					for (CaseDocument doc : documents) {
						int i = 0;
						try {
							i = doc.getContent().length;
						} catch (Exception ex) {
							System.out
									.println("Error Getting Document Contents.");
						}
						if (i > 0) {
							this.insertDocument(c, court, doc);
						}
					}
				}
				// 4. save scheduled events
				List<CaseEvent> events = filing.getEventList();
				if (events != null && !events.isEmpty()) {
					for (CaseEvent e : events) {
						if (e.getType().equalsIgnoreCase("121250")) // child
																	// support
																	// event
							this.insertCourtDate(c, e.getDate());
					}
				}

				// 5. save case record history
				// this.insertCaseRecordHistory(c, 2); // imported to CMS
				this.insertCaseRecordHistory(c, 13); // Readied for
														// Additional Filings
			}
		}
		
		return c.getUuid();
	}

	private void insertDocument(CaseRecord cr, Court court, CaseDocument caseDoc) {
		Documents doc = new Documents();
		doc.setCaseRecord(cr);
		if (caseDoc.getContent() != null && caseDoc.getContent().length > 0) {
			
			doc.setPhysicalType("pdf");
			doc.setStatus(new DocumentStatus(2, "imported"));
			DocumentInstance documentInstance = this.getModelFacade()
				.findGenericDocumentInstance(caseDoc.getType(), court);
			doc.setDocumentInstance(documentInstance);
			doc.setTitle(documentInstance.getDescription().replace(' ', '_'));
			doc.setReceivedDateTime(DateUtil.getCurrentDate()); //TODO: change to the date that was gotten from sustain
			this.getModelFacade().insertDocuments(doc);
			doc.setContent(null,caseDoc.getContent()); //first revision of the document is always NULL person
		}
	}

	private void insertCourtDate(CaseRecord cr, Date courtDate) {
		CourtEvents courtDateEvent = new CourtEvents();	
		courtDateEvent.setCaseRecord(cr);
		courtDateEvent.setEventTime(courtDate);
		CourtEventType eventType = this.getModelFacade().findCourtEventType(
				new Integer(1));
		courtDateEvent.setEventType(eventType);
		this.getModelFacade().insertCourtDate(courtDateEvent);
	}

	private Attorney checkBarIDinDataModle(String barID) {
		return this.getModelFacade().findAttorneyByBarID(barID);
	}

	private void insertAttorneyParticipant(CaseRecord cr,
			CaseOfficial attorney, int relationshipCode) {

		String barID = attorney.getBarID();
		Attorney attorneyFound = this.checkBarIDinDataModle(barID);
		if (attorneyFound == null) {
			// do nothing
		} else {
			// insert PersonParticipants only
			Person attPerson = this.getModelFacade().findPersonById(
					attorneyFound.getPerson().getUuid());
			ParticipantRelationship pr = this.getModelFacade()
					.findParticipantRelationship(relationshipCode);
			PersonParticipants pp = new PersonParticipants();
			pp.setCaseRecord(cr);
			pp.setPerson(attPerson);
			pp.setRelationship(pr);

			this.getModelFacade().insertPersonParticipants(pp);

		}
	}

	private void insertPersonParticipant(CaseRecord c, CaseParty party,
			int relationshipCode) {

		us.gaaoc.cms.sustain.vo.Person person = party.getPerson();
		String firstName = person.getFirstName();
		String middleName = person.getMiddleName();
		String lastName = person.getLastName();
		Person personFound = this.getModelFacade().findPersonByName(firstName,
				middleName, lastName);

		if (personFound == null) {
			// insert the person & PersonParticipants & personAddress
			Person p = new Person();
			p.setFirstName(firstName);
			p.setMiddleName(middleName);
			p.setLastName(lastName);

			this.getModelFacade().insertPerson(p);

			ParticipantRelationship pr = this.getModelFacade()
					.findParticipantRelationship(relationshipCode);
			PersonParticipants pp = new PersonParticipants();
			pp.setCaseRecord(c);
			pp.setPerson(p);
			pp.setRelationship(pr);

			this.getModelFacade().insertPersonParticipants(pp);

			/**
			 * Following code is blocked as giving the foreign key constrain while inserting into the person address table.
			 * In Future if wants to retrieve the address with the person then unblock the following code.
			 */
			/*List<us.gaaoc.cms.sustain.vo.Address> addList = person.getAddList();
			if (addList != null && !addList.isEmpty()) {
				for (us.gaaoc.cms.sustain.vo.Address add : addList) {
					PersonAddress pa = new PersonAddress();
					
					 * List <AddressType>addressTypeList = new ArrayList<AddressType>();
					 * AddressType at =
					 * this.getModelFacade().findAddressType(1); // street
					 * address addressTypeList.add(at);
					 
					Address address = new Address();
					String addressUuid = UUID.randomUUID().toString();
					address.setUuid(addressUuid);
					address.setCityName(add.getCity());
					address.setState(add.getState());
					address.setStreetFullText(add.getStreet1());
					address.setStreetExtensionText(add.getStreet2());
					address.setZipCode(add.getZip());
					int addressCategoryCode = 1; // for physical
					AddressCategory addressCategory = this.getModelFacade()
							.findAddressCateory(addressCategoryCode);
					int addressTypeCode = 1; // for primary contact
												// information
					AddressType addressType2 = this.getModelFacade()
							.findAddressType(addressTypeCode, addressCategory);
					Address address2 = null;// this.getModelFacade().findAddress(addressType2);

					
					 * pa.setAddressCategoryType(act);
					 * pa.setCityName(add.getCity());
					 * pa.setState(add.getState());
					 * pa.setStreetFullText(add.getStreet1());
					 * pa.setStreetExtensionText(add.getStreet2());
					 * pa.setZipCode(add.getZip());
					 * //pa.setPrimaryContactInfo(true);
					 

					pa.setPerson(p);
					pa.setAddress(address);
					pa.setAddressType(addressType2);
					String paUuid = UUID.randomUUID().toString();
					pa.setUuid(paUuid);
					this.getModelFacade().insertPersonAddress(pa);
				}
			}*/

		} else {
			// insert PersonParticipants and personAddress if needed
			ParticipantRelationship pr = this.getModelFacade()
					.findParticipantRelationship(relationshipCode);
			PersonParticipants pp = new PersonParticipants();
			pp.setCaseRecord(c);
			pp.setPerson(personFound);
			pp.setRelationship(pr);
			this.getModelFacade().insertPersonParticipants(pp);

			/**
			 * Following code is blocked as giving the foreign key constrain while inserting into the person address table.
			 * In Future if wants to retrieve the address with the person then unblock the following code.
			 */
/*			// check if personAddess has this record or not
			List<us.gaaoc.cms.sustain.vo.Address> addList = person.getAddList();
			if (addList != null && !addList.isEmpty()) {
				for (us.gaaoc.cms.sustain.vo.Address add : addList) {
					PersonAddress paFound = this.getModelFacade()
							.findPersonAddress(personFound);
					// add.getStreet1());
					if (paFound == null) {

						// insert personAddress
						PersonAddress pa = new PersonAddress();
						
						 * List <AddressType>addressTypeList = new ArrayList<AddressType>();
						 * AddressType at =
						 * this.getModelFacade().findAddressType(1); // street
						 * address addressTypeList.add(at);
						 
						// Address act = new Address();
						int addressCategoryCode = 1; // for physical
						AddressCategory addressCategory = this.getModelFacade()
								.findAddressCateory(addressCategoryCode);
						int addressTypeCode = 1; // for primary contact
													// information
						AddressType addressType2 = this.getModelFacade()
								.findAddressType(addressTypeCode,
										addressCategory);
						// Address address =
						// null;//this.getModelFacade().findAddress(addressType2);
						Address address = new Address();
						String addressUuid = UUID.randomUUID().toString();
						address.setUuid(addressUuid);
						address.setCityName(add.getCity());
						address.setState(add.getState());
						address.setStreetFullText(add.getStreet1());
						address.setStreetExtensionText(add.getStreet2());
						address.setZipCode(add.getZip());
						
						 * pa.setAddressCategoryType(act);
						 * pa.setCityName(add.getCity());
						 * pa.setState(add.getState());
						 * pa.setStreetFullText(add.getStreet1());
						 * pa.setStreetExtensionText(add.getStreet2());
						 * pa.setZipCode(add.getZip());
						 * //pa.setPrimaryContactInfo(true);
						 * 
						 
						pa.setPerson(personFound);
						// Added by Frank
						pa.setAddress(address);
						pa.setAddressType(addressType2);
						String paUuid = UUID.randomUUID().toString();
						// End
						this.getModelFacade().insertPersonAddress(pa);
					}
				}
			}*/
		}
	}

	private void insertOrgParticipant(CaseRecord c, CaseParty party,
			int relationshipCode) {

		us.gaaoc.cms.sustain.vo.Organization org = party.getOrg();
		String orgName = org.getName().trim();
		Organizations orgFound = this.getModelFacade().findOrganizationByName(
				orgName);

		if (orgFound == null) {
			// insert org & orgParticipants & orgAddress
			Organizations o = new Organizations();
			o.setName(orgName);
			this.getModelFacade().insertOrganizations(o);

			OrgParticipants op = new OrgParticipants();
			op.setCaseRecord(c);
			op.setOrganizations(o);
			ParticipantRelationship pr = this.getModelFacade()
					.findParticipantRelationship(relationshipCode);
			op.setRelationship(pr);

			this.getModelFacade().insertOrgParticipants(op);

			List<us.gaaoc.cms.sustain.vo.Address> addList = org.getAddList();
			if (addList != null && !addList.isEmpty()) {
				for (us.gaaoc.cms.sustain.vo.Address add : addList) {
					int addressCategoryCodeForPhysical = 1; // for physical
															// address
					int addressCategoryCodeForMailing = 1; // for mailing
															// address
					AddressCategory addressCategory_physical = this
							.getModelFacade().findAddressCateory(
									addressCategoryCodeForPhysical);
					AddressCategory addressCategory_mailing = this
							.getModelFacade().findAddressCateory(
									addressCategoryCodeForMailing);
					int addressTypeCode = 1; // for primaryContact
												// information
					AddressType addressType_physical = this.getModelFacade()
							.findAddressType(addressTypeCode,
									addressCategory_physical);
					AddressType addressType_mailing = this.getModelFacade()
							.findAddressType(addressTypeCode,
									addressCategory_physical);
					Address address = new Address();
					address.setCityName(add.getCity());
					address.setState(add.getState());
					address.setZipCode(add.getZip());
					address.setStreetFullText(add.getStreet1());
					address.setStreetExtensionText(add.getStreet2());

					OrganizationAddress organizationAddress_p = new OrganizationAddress();
					organizationAddress_p.setAddressType(addressType_physical);
					organizationAddress_p.setOrganization(o);
					organizationAddress_p.setAddress(address);
					this.getModelFacade().insertOrganizationAddress(
							organizationAddress_p);

					OrganizationAddress organizationAddress_m = new OrganizationAddress();
					organizationAddress_m.setAddressType(addressType_mailing);
					organizationAddress_m.setOrganization(o);
					organizationAddress_m.setAddress(address);
					this.getModelFacade().insertOrganizationAddress(
							organizationAddress_m);
				}
			}

		} else {
			// insert orgParticipants and orgAddress if needed
			ParticipantRelationship pr = this.getModelFacade()
					.findParticipantRelationship(relationshipCode);
			OrgParticipants op = new OrgParticipants();
			op.setCaseRecord(c);
			op.setOrganizations(orgFound);
			op.setRelationship(pr);

			this.getModelFacade().insertOrgParticipants(op);

			// check if orgAddess has this record or not
			List<us.gaaoc.cms.sustain.vo.Address> addList = org.getAddList();
			if (addList != null && !addList.isEmpty()) {
				for (us.gaaoc.cms.sustain.vo.Address add : addList) {
					Organizations organizationFound =
					this.getModelFacade().findOrganizationByName(orgFound.getName());

					// OrganizationAddress oaFound =
					// this.getModelFacade().findOrgAddress(orgFound,add.getStreet1());
					if (organizationFound == null) {
					/*
					 * // insert orgAddress OrganizationAddress oa = new
					 * OrganizationAddress(); AddressType at =
					 * this.getModelFacade().findAddressType(2); // mailing
					 * address oa.setAddressType(at);
					 * oa.setCityName(add.getCity());
					 * oa.setState(add.getState()); oa.setZipCode(add.getZip());
					 * oa.setStreetFullText(add.getStreet1());
					 * oa.setStreetExtensionText(add.getStreet2());
					 * oa.setPrimaryContactInfo(true);
					 * oa.setOrganization(orgFound);
					 */
					int addressCategoryCodeForPhysical = 1; // for physical
															// address
					int addressCategoryCodeForMailing = 1; // for mailing
															// address
					AddressCategory addressCategory_physical = this
							.getModelFacade().findAddressCateory(
									addressCategoryCodeForPhysical);
					AddressCategory addressCategory_mailing = this
							.getModelFacade().findAddressCateory(
									addressCategoryCodeForMailing);
					int addressTypeCode = 1; // for primaryContact
												// information
					AddressType addressType_physical = this.getModelFacade()
							.findAddressType(addressTypeCode,
									addressCategory_physical);
					AddressType addressType_mailing = this.getModelFacade()
							.findAddressType(addressTypeCode,
									addressCategory_physical);

					Address address = new Address();
					address.setCityName(add.getCity());
					address.setState(add.getState());
					address.setZipCode(add.getZip());
					address.setStreetFullText(add.getStreet1());
					// Frank added the following three lines
					String aUuid = UUID.randomUUID().toString();
					address.setUuid(aUuid);
					this.getModelFacade().insertAddress(address);

					address.setStreetExtensionText(add.getStreet2());

					OrganizationAddress organizationAddress_p = new OrganizationAddress();
					organizationAddress_p.setAddressType(addressType_physical);
					organizationAddress_p.setOrganization(orgFound);
					organizationAddress_p.setAddress(address);
					// Frank added the following two lines
					String oapUuid = UUID.randomUUID().toString();
					organizationAddress_p.setUuid(oapUuid);

					this.getModelFacade().insertOrganizationAddress(
							organizationAddress_p);

					OrganizationAddress organizationAddress_m = new OrganizationAddress();
					organizationAddress_m.setAddressType(addressType_mailing);
					organizationAddress_m.setOrganization(orgFound);
					organizationAddress_m.setAddress(address);
					// Frank added the following two lines
					String oamUuid = UUID.randomUUID().toString();
					organizationAddress_m.setUuid(oamUuid);

					this.getModelFacade().insertOrganizationAddress(
							organizationAddress_m);
					}
				}
			}
		}
	}

	// Frank }

	private CaseRecord insertCaseRecord(CaseFiling c, Court court) {
		CaseRecord cr = new CaseRecord();
		String caseRecordUuid = UUID.randomUUID().toString();
		cr.setUuid(caseRecordUuid);
		cr.setCaseTrackingId(c.getDocketID());
		cr.setInstantiationDateTime(c.getDate());
		cr.setSubmittedDateTime(c.getDate());
		cr.setCaseType(new CaseRecordType(1, "ChildSupportEnforcement"));

		if (c.getDispostionDate() != null) {
			cr.setDispositionDate(c.getDispostionDate());
			cr.setStatus(new CaseRecordStatus(6, "Disposed"));
		} else
			//cr.setStatus(new CaseRecordStatus(15, "UnsentAddition"));
			cr.setStatus(new CaseRecordStatus(2, "Imported"));

		cr.setClearFilingFlag(false);
		cr.setArchivedFlag(false);
		cr.setCommunicationFailed(false);
		cr.setDeletedFilingFlag(false);
		LocalCaseType localCaseType = this.getModelFacade()
				.findLocalCaseTypeByCourtandCode(court, c.getType());
		LocalCaseDivision localCaseDivision = this.getModelFacade()
				.findLocalCaseDivisionByCourtandCode(court, c.getDivID());
		LocalCaseCategory localCaseCategory = this.getModelFacade()
				.findLocalCaseCategoryByCourtandCode(court, c.getCategory());
		LocalCaseFilingType localCaseFilingType = this
				.getModelFacade()
				.findLocalCaseFilingTypeByCourtandCode(court, c.getFilingType());
		cr.setLocalCaseCategory(localCaseCategory);
		cr.setLocalCaseDivision(localCaseDivision);
		cr.setLocalCaseFilingType(localCaseFilingType);
		cr.setLocalCaseType(localCaseType);
		cr.setCourt(court);
		return this.getModelFacade().insertCaseRecord(cr, court.getUuid());

	}

	private void insertCaseRecordHistory(CaseRecord cr, int eventTypeCode) {
		CaseRecordHistory crh = new CaseRecordHistory();
		crh.setCaseRecord(cr);
		crh.setEventDateTime(DateUtil.getCurrentDate());
		CaseRecordEventType crt = this.getModelFacade()
				.findCaseRecordEventType(new Integer(eventTypeCode));
		crh.setEventType(crt);
		this.getModelFacade().insertCaseRecordHistory(crh);
	}

	private ModelFacade getModelFacade() {
		return ModelFacadeHibernate.getInstance();
	}

}
